/*
 * File:   main.cpp
 * Author: Gab'z
 *
 * Created on 1 mai 2012, 19:45
 */

//#include <QtGui/QApplication>
#include <iostream>
#include "Entier.h"
#include "Rationnel.h"
#include "Reel.h"
#include "Complexe.h"
#include "LogMessage.h"
#include "LogSystem.h"
#include "Expression.h"
#include "Constante.h"
#include "Nombre.h"
#include "NombreSimple.h"
#include "CalcParser.h"
#include "Pile.h"
#include "Add.h"
#include <cmath>
#include <exception>

using namespace std;

int main(int argc, char *argv[]) {
    // initialize resources, if needed
    // Q_INIT_RESOURCE(resfile);

    // QApplication app(argc, argv);

    // create and show your widgets here
    LogSystem::log(LogMessage(1, "Debut Main"));
    //return app.exec();
    Entier e1 = Entier(5);
    Entier e2 = Entier(-2);
    std::cout << "addition " << e1 + e2 << "\n";
    std::cout << "soustrac " << e1 - e2 << "\n";
    std::cout << "multipli " << e1 * e2 << "\n";
    std::cout << "division " << e1 / e2 << "\n";
    std::cout << "modulo " << e1 % e2 << "\n\n";

    Rationnel ra1 = Rationnel(5, 2);
    Rationnel ra2 = Rationnel(-2, 3);
    std::cout << "addition " << ra1 + ra2 << "\n";
    std::cout << "soustrac " << ra1 - ra2 << "\n";
    std::cout << "multipli " << ra1 * ra2 << "\n";
    std::cout << "division " << ra1 / ra2 << "\n\n";

    Reel re1 = Reel(5.4);
    Reel re2 = Reel(-2);
    Reel re3 = Reel(e2);
    std::cout << "addition " << re1 + re2 << "\n";
    std::cout << "soustrac " << re1 - re2 << "\n";
    std::cout << "multipli " << re1 * re2 << "\n";
    std::cout << "division " << re1 / re2 << "\n";
    std::cout << "creation <- Entier " << re3 << "\n\n";
    //    system("pause");
    cout << "ligne test\n\n";

    std::cout << "addition " << re1 + e2 << "\n";
    std::cout << "addition " << e1 + ra2 << "\n";

    Complexe c = Complexe(&ra1, &re2);
    std::cout << "complexe = " << c << "\n" << "\n";
    //ConstanteSimple* cs3 =  *cs1 + *cs2;
    /*    Complexe c1 = Complexe(e1,e2);
        Complexe c2 = Complexe(ra1,ra2);
        Complexe c3 = c1 + c2;
     **/
    //LogMessage m = LogMessage(1, "Essai du log"); p_cse1 = &e1;
    NombreSimple* p_cs1 = &e1;
    NombreSimple* p_cs2 = &e2;
    NombreSimple* p_cs3 = &re1;
    NombreSimple* p_cs4 = &re2;


    Entier* p_cse1 = dynamic_cast<Entier*> (p_cs1);
    if (p_cse1 != 0) {
        cout << "cast Entier vers Entier\n";
        cout << *p_cse1 << "\n";
    } else {
        cout << "cast Entier vers Entier BAM !!\n";
    }
    Reel* p_cse2 = dynamic_cast<Reel*> (p_cs2);
    if (p_cse2 != 0) {
        cout << "cast Entier vers Reel\n";
    } else {
        cout << "cast Entier vers Reel BAM !!\n";
    }
    Entier* p_csre1 = dynamic_cast<Entier*> (p_cs3);
    if (p_csre1 != 0) {
        cout << "cast Reel vers Entier\n";
    } else {
        cout << "cast Reel vers Entier BAM !!\n";
    }
    Reel* p_csre2 = dynamic_cast<Reel*> (p_cs4);
    if (p_csre2 != 0) {
        cout << "cast Reel vers Reel\n";
        cout << *p_csre2 << "\n";
        cout << *p_csre2 + *p_cse1 << " WAW !\n";
    } else {
        cout << "cast Reel vers Reel BAM !!\n";
    }

    NombreSimple* cs_new = add(p_csre2, p_cse1);
    Reel* p_reel = dynamic_cast<Reel*> (cs_new);
    cout << *p_reel << "YEAH !\n";

    Complexe comp = Complexe(&e2, &ra1);
    cout << comp << "\n";
    Complexe comp2 = Complexe(re1);
    cout << comp2 << "\n";
    Complexe comp3 = comp + comp2;
    cout << "comp + comp2 = " << comp3 << "\n";
    Complexe comp4 = comp + e1;
    cout << "comp + e1 = " << comp4 << "\n";


    Complexe comp5 = comp - comp2;
    cout << "comp - comp2 = " << comp5 << "\n";
    Complexe comp6 = comp - e1;
    cout << "comp - e1 = " << comp6 << "\n";

    Complexe co1 = Complexe(Entier(5), Rationnel(9, 2));
    Complexe co2 = Complexe(Reel(4.1), Rationnel(7, 2));
    Complexe co3 = co1 * co2;
    cout << co1 << " * " << co2 << " = " << co3 << "\n";

    Complexe co4 = Complexe(Entier(0), Entier(1));
    Complexe co5 = co4 * co4;
    cout << co4 << " * " << co4 << " = " << co5 << "\n";

    Complexe co6 = Complexe(Entier(5), Rationnel(9, 2));
    Complexe co7 = Complexe(Reel(4.1), Rationnel(7, 2));
    Complexe co8 = co6 / co7;
    cout << co6 << " / " << co7 << " = " << co8 << "\n";

    cout << "sin(" << *p_cs1 << ")" << " = " << sin(*p_cs1) << "\n";

    try {
        CalcParser cp = CalcParser();
        int i;
        int* pos = &i;
        if (cp.isEntier("45")) cout << "45 est un entier\n";
        if (cp.isRationnel("4/5", pos)) cout << "4/5 est un rationnel\n";
        if (cp.isReel("4.5", pos)) cout << "4.5 est un réel\n";
        if (cp.isComplexe("4$5", pos)) cout << "4$5 est un COMPLEXE\n";
        if (cp.isComplexe("4$5/7", pos)) cout << "4$5/7 est un COMPLEXE\n";
        if (cp.isComplexe("4$5.2", pos)) cout << "4$5.2 est un COMPLEXE\n";
        if (cp.isComplexe("4/7$5", pos)) cout << "4/7$5 est un COMPLEXE\n";
        if (cp.isComplexe("4.7$5", pos)) cout << "4.7$5 est un COMPLEXE\n";
        if (cp.isComplexe("4/7$5.7", pos)) cout << "4/7$5.7 est un COMPLEXE\n";
        if (cp.isComplexe("4.7$5.7", pos)) cout << "4.7$5.7 est un COMPLEXE\n";


        if (!cp.isComplexe("4$3$5.", pos)) cout << "4$3$5 n'est PAS un COMPLEXE\n";
        if (!cp.isComplexe("4$", pos)) cout << "4$ n'est PAS un COMPLEXE\n";
        if (!cp.isComplexe("4$/", pos)) cout << "4$/ n'est PAS un COMPLEXE\n";
        if (!cp.isComplexe("4/", pos)) cout << "4/ n'est PAS un COMPLEXE\n";
        if (!cp.isComplexe("4..7$5", pos)) cout << "4..7$5 n'est PAS un COMPLEXE\n";
        if (!cp.isComplexe("04/07$5//7", pos)) cout << "04/07$5./7 n'est PAS un COMPLEXE\n";
        if (cp.isComplexe("4.700$5.700", pos)) cout << "4.700$5.700 est un COMPLEXE\n";



        CalcObjet* p_cTestParse = cp.parse("5");
        Entier* p_cTestCast = dynamic_cast<Entier*> (p_cTestParse);
        if (p_cTestCast != 0) cout << "Résultat du parse de la string \"5\" : " << *p_cTestCast << "\n";
        else cout << "echec parsing de 5\n";

        CalcObjet* p_cTestParse2 = cp.parse("5/4");
        Rationnel* p_cTestCast2 = dynamic_cast<Rationnel*> (p_cTestParse2);
        if (p_cTestCast2 != 0) cout << "Résultat du parse de la string \"5/4\" : " << *p_cTestCast2 << "\n";
        else cout << "echec parsing de 5/4\n";

        CalcObjet* p_cTestParse3 = cp.parse("57/40");
        Rationnel* p_cTestCast3 = dynamic_cast<Rationnel*> (p_cTestParse3);
        if (p_cTestCast3 != 0) cout << "Résultat du parse de la string \"57/40\" : " << *p_cTestCast3 << "\n";
        else cout << "echec parsing de 57/40\n";

        CalcObjet* p_cTestParse4 = cp.parse("21.45");
        Reel* p_cTestCast4 = dynamic_cast<Reel*> (p_cTestParse4);
        if (p_cTestCast4 != 0) cout << "Résultat du parse de la string \"21.45\" : " << *p_cTestCast4 << "\n";
        else cout << "echec parsing de 21.45\n";

        CalcObjet* p_cTestParse5 = cp.parse("45$40");
        Complexe* p_cTestCast5 = dynamic_cast<Complexe*> (p_cTestParse5);
        if (p_cTestCast5 != 0) cout << "Résultat du parse de la string \"45$40\" : " << *p_cTestCast5 << "\n";
        else cout << "echec parsing de 45$40\n";

        CalcObjet* p_cTestParse6 = cp.parse("45$40/2");
        Complexe* p_cTestCast6 = dynamic_cast<Complexe*> (p_cTestParse6);
        if (p_cTestCast6 != 0) cout << "Résultat du parse de la string \"45$40/2\" : " << *p_cTestCast6 << "\n";
        else cout << "echec parsing de 45$40/2\n";

        CalcObjet* p_cTestParse7 = cp.parse("45$40.2");
        Complexe* p_cTestCast7 = dynamic_cast<Complexe*> (p_cTestParse7);
        if (p_cTestCast7 != 0) cout << "Résultat du parse de la string \"45$40.2\" : " << *p_cTestCast7 << "\n";
        else cout << "echec parsing de 45$40.2\n";

        CalcObjet* p_cTestParse8 = cp.parse("45/2$40");
        Complexe* p_cTestCast8 = dynamic_cast<Complexe*> (p_cTestParse8);
        if (p_cTestCast8 != 0) cout << "Résultat du parse de la string \"45/2$40\" : " << *p_cTestCast8 << "\n";
        else cout << "echec parsing de 45/2$40\n";

        CalcObjet* p_cTestParse9 = cp.parse("45.2$40/3");
        Complexe* p_cTestCast9 = dynamic_cast<Complexe*> (p_cTestParse9);
        if (p_cTestCast9 != 0) cout << "Résultat du parse de la string \"45.2$40/3\" : " << *p_cTestCast9 << "\n";
        else cout << "echec parsing de 45.2$40/3\n";

        CalcObjet* p_cTestParse10 = cp.parse("45.2$40../3");
        Complexe* p_cTestCast10 = dynamic_cast<Complexe*> (p_cTestParse10);
        if (p_cTestCast10 != 0) cout << "Résultat du parse de la string \"45.2$40..\" : " << *p_cTestCast10 << " F\n";
        else cout << "echec parsing de 45.2$40../3\n";

        LogSystem::log(LogMessage(1, "Fin Main"));
    } catch (ConstanteFormatException e) {
        cout << "Echec bien capturé !!\n###################\n"<< e.what() << "\n#######################\n";
    }

    // ne PAS permettre d'une manière ou d'une autre l'addition de constantes sans PASser par un opérateur
    // l'opérateur prend en charge le test pour déterminer si une constante est une expression et la modifiera de la bonne façon
    // on ne peut faire ces petites opérations (add, sub, mul, div) qu'avec des objets de type Nombre
    // Expression* exp = new Expression("A B +");
    // Constante* cs_exp = add(e1,*exp);


    Pile* pile = new Pile();
    cout << "taille de la pile = " << pile->size() << "\n";

    Entier* pe = new Entier(1);
    Rationnel* pra = new Rationnel(1, 2);
    pile->push(pe);
    pile->push(pra);
    cout << "taille de la pile = " << pile->size() << "\n";
    cout << "Sommet de la pile = " << *(pile->top()) << "\n";
    pile->pop();
    cout << "taille de la pile = " << pile->size() << "\n";
    cout << "Sommet de la pile = " << *(pile->top()) << "\n";
    pile->push(pra);
    cout << "taille de la pile = " << pile->size() << "\n";
    CalcParser* calcParser = new CalcParser();
    Operateur* p_operator = 0;
    if (calcParser->isOperateur("+")) cout << "+ est un operateur\n";
    else cout << "+ n'est pas un operateur\n";
    CalcObjet* p_calc_objet = calcParser->parse("+");
    p_operator = dynamic_cast<Operateur*> (p_calc_objet);
    cout << *p_operator << "\n";


    try {
        p_operator->execute(pile);
    } catch (exception e) {
        cout << e.what();
    }

    cout << "taille de la pile = " << pile->size() << "\n";
    cout << "Sommet de la pile = " << *(pile->top()) << "\n";
    delete pile;
    return 0;
}
